﻿using Google.Protobuf;
using ServerCommon.Log;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServerCommon.Net;

namespace Pb
{
    public interface IProtocol
    {
        int ProtocolId { get; }
        void OnProcess(NetNode netService, NetSession node);
        void OnProcess(NetSession node);
        void OnProcess(Guid sessionId);
        public byte[] Serialize(bool withLength = true);
        int Size();
    }

    public class Protocol<T> : IProtocol where T : class, IMessage<T>, new()
    {
        private static readonly LogHelper Log = LogHelper.GetLogger(typeof(T));

        // ReSharper disable once StaticMemberInGenericType
        public static int StaticProtocolId { get; set; }

        public int ProtocolId => StaticProtocolId;

        public virtual void OnProcess(Guid sessionId)
        {
        }

        public virtual void OnProcess(NetNode netService, NetSession node)
        {
        }

        public virtual void OnProcess(NetSession session)
        {
        }

        public int Size()
        {
            var msg = this as T;
            Debug.Assert(msg != null);
            return msg.CalculateSize();
        }

        private const int ProtocolSizeDomainLength = sizeof(int);
        private const int ProtocolIdDomainLength = sizeof(int);

        // 把协议转换成二进制数据
        // [Size] + ProtocolId + PbMsgContent
        public byte[] Serialize(bool withLength = false)
        {
            if (ProtocolId == 0)
            {
                Log.Error($"Serialize 序列化协议失败, ProtocolId=0, {this}");
                return null;
            }

            var msg = this as T;
            Debug.Assert(msg != null);
            var msgSize = msg.CalculateSize();

            var buffer = withLength ? new byte[ProtocolSizeDomainLength + ProtocolIdDomainLength + msgSize] : new byte[ProtocolIdDomainLength + msgSize];
            var serializedLength = 0;
            if (withLength)
            {
                var dataLengthBytes = BitConverter.GetBytes(ProtocolIdDomainLength + msgSize);
                Buffer.BlockCopy(dataLengthBytes, 0, buffer, serializedLength, ProtocolSizeDomainLength);
                serializedLength += ProtocolSizeDomainLength;
            }
            var protocolIdBytes = BitConverter.GetBytes(ProtocolId);
            Buffer.BlockCopy(protocolIdBytes, 0, buffer, serializedLength, protocolIdBytes.Length);
            serializedLength += protocolIdBytes.Length;

            Buffer.BlockCopy(msg.ToByteArray(), 0, buffer, serializedLength, msgSize);
            return buffer;
        }
    }
}
